package com.shu.logsearch.util;

import org.apache.tools.tar.TarEntry;
import org.apache.tools.tar.TarInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * 解压工具类
 *
 * @author Tree Cai
 * @date 2019/7/4
 */
public class ZipUtil {

    private static Logger logger = LoggerFactory.getLogger(ZipUtil.class);

    /**
     * 解压.gz格式文件，解压后文件存放在同一级文件夹
     *
     * @param source 源文件路径，不能为空
     */
    public static void unGzipFile(String source, String outputFilePath) {
        AssertUtil.notNull(source);
        unGzipFile(MyFileUtil.touch(source), outputFilePath);
    }

    /**
     * 将gz格式文件解压为指定文件
     *
     * @param file           gz格式的源文件，不能为空
     * @param outputFilePath 目标文件路径，为空时默认解压到跟源文件相同目录下
     */
    public static void unGzipFile(File file, String outputFilePath) {
        boolean success = true;
        List<File> successFileList = new ArrayList<>();
        try {
            AssertUtil.notNull(file);
            Assert.isTrue("gz".equalsIgnoreCase(MyFileUtil.extName(file)), "文件格式错误：file只能是.gz格式的文件！");
            String filePath = MyFileUtil.getAbsolutePath(file);
            String fileName = MyFileUtil.getName(file);
            if (StringUtils.isEmpty(outputFilePath))//输出路径为空时，则输出到源文件所在目录
                outputFilePath = filePath.substring(0, filePath.length() - ".gz".length());
            if (MyFileUtil.isDirectory(outputFilePath))//输出路径不为
                outputFilePath += fileName.substring(0, fileName.length() - ".gz".length());

            File outputFile = MyFileUtil.touch(outputFilePath);
            MyIOStreamUtil.transferTo(new GZIPInputStream(new FileInputStream(file)), new FileOutputStream(outputFile), true);
            successFileList.add(outputFile);
        } catch (Exception e) {
            logger.error("解压.gz文件出错！");
            success = false;
            e.printStackTrace();
        } finally {
            if (!success)//异常进行回滚
                MyFileUtil.delete(successFileList);
        }
    }

    /**
     * 解压zip文件到outputDir目录
     *
     * @param source
     * @param outputDir
     */
    public static void unZip(String source, String outputDir) {
        AssertUtil.notNull(source);
        unGzipFile(MyFileUtil.touch(source), outputDir);
    }

    /**
     * 解压zip文件到outputDir目录
     *
     * @param file
     * @param outputDir
     */
    public static void unZip(File file, String outputDir) {
        ZipFile zipFile = null;
        List<File> successFileList = new ArrayList<>();
        boolean success = true;
        try {
            AssertUtil.notNull(file);
            Assert.isTrue("zip".equalsIgnoreCase(MyFileUtil.extName(file)), "文件格式错误：file只能是zip格式的文件！");
            if (StringUtils.isEmpty(outputDir))
                outputDir = MyFileUtil.getDir(MyFileUtil.getAbsolutePath(file));

            Charset CP866 = Charset.forName("CP866");
            zipFile = new ZipFile(file, CP866);
            MyFileUtil.getOrCreateDir(outputDir);
            Enumeration<?> enums = zipFile.entries();
            while (enums.hasMoreElements()) {//遍历压缩文件中的文件或文件夹
                ZipEntry zipEntry = (ZipEntry) enums.nextElement();
                if (zipEntry.isDirectory())//目录
                    MyFileUtil.getOrCreateDir(outputDir, zipEntry.getName());
                else {//文件
                    File tempFile = new File(outputDir + "/" + zipEntry.getName());
                    MyFileUtil.getOrCreateDir(tempFile.getParent() + "/");
                    MyIOStreamUtil.transferTo(zipFile.getInputStream(zipEntry), new FileOutputStream(tempFile), true);
                    successFileList.add(tempFile);
                }
            }
        } catch (Exception e) {
            logger.error("解压zip文件出错！");
            success = false;
            e.printStackTrace();
        } finally {
            CloseUtil.close(zipFile);
            if (!success)//异常进行回滚
                MyFileUtil.delete(successFileList);
        }
    }


    /**
     * 解压tar.gz文件
     *
     * @param sourcePath
     * @param outputDir
     */
    public static void unTarGz(String sourcePath, String outputDir) {
        assert !StringUtils.isEmpty(sourcePath) : "参数非法：sourcePath不能为空！";
        unTarGz(MyFileUtil.touch(sourcePath), outputDir);
    }

    /**
     * 解压tar.gz文件
     *
     * @param file
     * @param outputDir
     */
    public static void unTarGz(File file, String outputDir) {
        TarInputStream tarInputStream = null;
        List<File> successFileList = new ArrayList<>();
        boolean success = true;
        try {
            AssertUtil.notNull(file);
            Assert.isTrue("tar.gz".equalsIgnoreCase(MyFileUtil.extName(file)), "文件格式错误：file只能是tar.gz格式的文件！");
            if (StringUtils.isEmpty(outputDir))
                outputDir = MyFileUtil.getDir(MyFileUtil.getAbsolutePath(file));

            tarInputStream = new TarInputStream(new GZIPInputStream(new BufferedInputStream(new FileInputStream(file))), 1024 * 2);
            MyFileUtil.getOrCreateDir(outputDir);
            TarEntry tarEntry = null;
            while ((tarEntry = tarInputStream.getNextEntry()) != null) {
                if (tarEntry.isDirectory())//是目录
                    MyFileUtil.getOrCreateDir(outputDir, tarEntry.getName());
                else {//是文件
                    File tempFile = new File(outputDir + "/" + tarEntry.getName());
                    MyFileUtil.getOrCreateDir(tempFile.getParent() + "/");
                    MyIOStreamUtil.transferTo(tarInputStream, new FileOutputStream(tempFile), false);
                    successFileList.add(tempFile);
                }
            }
        } catch (Exception e) {
            logger.error("解压tar.gz文件出错！");
            success = false;
            e.printStackTrace();
        } finally {
            CloseUtil.close(tarInputStream);
            if (!success)//异常进行回滚
                MyFileUtil.delete(successFileList);
        }
    }


    public static void main(String[] args) {
//        String source = "file/catalina.out-20190522020021.tar.gz12";
        String source = "file/1.123123";
        unZip(MyFileUtil.touch(source), null);
//        unGzipFile(MyFileUtil.touch(source), null);
//        unTarGz(MyFileUtil.touch(source), null);
    }
}
